tree grammar CSyntaxTree;

options
{
	tokenVocab=C;
	ASTLabelType=CommonTree;
	output=template;
	backtrack=true;
}

scope SymbolScope
{
	HashMap<String, CommonTree> symbolTable;
}

scope FunctionScope
{
	int counter;
}

@header
{
import java.util.HashMap;
}

@members
{
}

translation_unit
scope SymbolScope;
@init
{
	$SymbolScope::symbolTable = new HashMap<String, CommonTree>();
}
	: ins+=external_declaration+ -> llvm(instructions={$ins})
	;

external_declaration
	: function_definition -> echo(text={$function_definition.st})
	| declaration -> echo(text={$declaration.st})
	;

function_definition
scope SymbolScope, FunctionScope;
@init
{
	$SymbolScope::symbolTable = new HashMap<String, CommonTree>();
	$FunctionScope::counter = 0;
}
	:	^(FUNCTION function_declarator compound_statement)
		-> function(head={$function_declarator.st}, body={$compound_statement.st})
	;

function_declarator
	:	type IDENTIFIER function_declarator_suffix
		-> function_head(return_type={((TypeTree)$type.start).llvmType}, id={$IDENTIFIER.text},
			params={$function_declarator_suffix.st})
	;

function_declarator_suffix
	:	^(PARAMETER_LIST parameter_type_list)
		-> echo(text={$parameter_type_list.st})
	|	PARAMETER_LIST -> empty()
	;

parameter_type_list
	: parameter_list VARARGS? -> echo(text={$parameter_list.st}) // TODO
	;

parameter_list
	: d+=parameter_declaration+ -> echo(text={$d})
	;

parameter_declaration
	: ^(VARIABLE declarator) -> echo(text={$declarator.st})
	;

declaration
	: ^(VARIABLE declarator initializer?)
	;

declarator
	: type IDENTIFIER { System.out.println(((TypeTree)$start).llvmType); }
	-> local_variable(type={((TypeTree)$type.start).llvmType}, id={$IDENTIFIER.text})
	;

initializer
	: expression
	| ^(INITIALIZER_LIST initializer_list)
	;

initializer_list
	: initializer+
	;

storage_class_specifier
	: EXTERN
	| STATIC
	| AUTO
	| REGISTER
	;

type_specifier
	: VOID
	| CHAR
	| SHORT
	| INT
	| LONG
	| FLOAT
	| DOUBLE
	| SIGNED
	| UNSIGNED
	;

type_qualifier
	: CONST
	| VOLATILE
	;

type
	: array_type
	| pointer_type
	| basic_type
	;

array_type
	:	^(ARRAY array_type (expression | UNDEFINED)) // constant expression
	|	^(ARRAY pointer_type (expression | UNDEFINED)) // constant expression
	|	^(ARRAY basic_type (expression | UNDEFINED)) // constant expression
	;

pointer_type
	:	^(POINTER pointer_type type_qualifier*)
	|	^(POINTER basic_type type_qualifier*)
	;

basic_type
	:	^(BASIC_TYPE
			( storage_class_specifier
			| type_specifier
			| type_qualifier
			)+
		)
	|	UNDEFINED
	;

type_name
	: pointer_type
	| basic_type
	;

// E x p r e s s i o n s

argument_expression_list
	: expression (expression)*
	;

expression returns [CommonTree type]
	:	^('+' e1=expression e2=expression)
		-> add(exp1={$e1.st},exp2={$e2.st},
			addr={$FunctionScope::counter++})

	|	^('-' e1=expression e2=expression)
		-> sub(exp1={$e1.st},exp2={$e2.st},
			addr={$FunctionScope::counter++})

	|	^('*' e1=expression e2=expression)
		-> mul(exp1={$e1.st},exp2={$e2.st},
			addr={$FunctionScope::counter++})

	|	^('/' e1=expression e2=expression)
		-> div(exp1={$e1.st},exp2={$e2.st},
			addr={$FunctionScope::counter++})

	|	^('%' e1=expression e2=expression)
	|	^(CAST type_name expression)

	|	^(PREFIX_INC e=expression)
		-> prefix_inc(exp={$e.st},addr={$FunctionScope::counter++})

	|	^(PREFIX_DEC e=expression)
		-> prefix_inc(exp={$e.st},addr={$FunctionScope::counter++})

	|	^('&' expression)
	|	^('*' expression)
	|	^('+' expression)
	|	^('-' expression)
	|	^(SIZEOF expression)
	|	^(SIZEOF type_name)

	|	^(INDEX e1=expression e2=expression)
		-> index(base={$e1.st},index={$e2.st})

	|	^(CALL e=expression args=argument_expression_list?)
		-> call(func={$e.st},args={$args.st})

	|	^(MEMBER_ACCESS expression IDENTIFIER)
	|	^(INDIRECT_MEMBER_ACCESS expression IDENTIFIER)

	|	^(POSTFIX_INC e=expression)
		-> postfix_inc(exp={$e.st}, addr={$FunctionScope::counter++})

	|	^(POSTFIX_DEC e=expression)
		-> postfix_dec(exp={$e.st}, addr={$FunctionScope::counter++})

	|	^(CONDITIONAL expression expression expression)

	|	^('||' e1=expression e2=expression)
		-> logical_or(exp1={$e1.st},exp2={$e2.st},
			addr={$FunctionScope::counter++},
			label={$FunctionScope::counter++})

	|	^('&&' e1=expression e2=expression)
		-> logical_and(exp1={$e1.st},exp2={$e2.st},
			addr={$FunctionScope::counter++},
			label={$FunctionScope::counter++})

	|	^('!' e=expression)
		-> logical_not(exp={$e.st},addr={$FunctionScope::counter++})

	|	^('~' expression)
	|	^('|' expression expression)
	|	^('^' expression expression)
	|	^('&' expression expression)

	|	^(('=='|'!=') expression expression)
	|	^(('<'|'>'|'<='|'>=') expression expression)

	|	^(('<<'|'>>') expression expression)

	|	^('=' e1=expression e2=expression) // lvalue
		-> assign(exp1={$e1.st},exp2={$e2.st},addr={$FunctionScope::counter++})
	|	^(assignment_operator expression expression) // lvalue
	|	^(COMMA expression expression)
	|	IDENTIFIER -> variable(exp={$st},addr={$text})
	|	e=constant -> hidden(text={$e.value})
	;

constant returns [String value]
	:	HEX_LITERAL
	|	OCTAL_LITERAL
	|	DECIMAL_LITERAL { $value = $DECIMAL_LITERAL.text; }
	|	CHARACTER_LITERAL
	|	STRING_LITERAL
	|	FLOATING_POINT_LITERAL
	;

assignment_operator
	: '*='
	| '/='
	| '%='
	| '+='
	| '-='
	| '<<='
	| '>>='
	| '&='
	| '^='
	| '|='
	;


// S t a t e m e n t s

statement
	: s=labeled_statement -> echo(text={$s.st})
	| s=compound_statement -> echo(text={$s.st})
	| s=expression_statement -> echo(text={$s.st})
	| s=selection_statement -> echo(text={$s.st})
	| s=iteration_statement -> echo(text={$s.st})
	| s=jump_statement -> echo(text={$s.st})
	;

labeled_statement
	: ^(LABEL IDENTIFIER statement)
	| ^(CASE expression statement) // constant
	| ^(DEFAULT statement)
	;

compound_statement
scope SymbolScope;
@init
{
	$SymbolScope::symbolTable = new HashMap<String, CommonTree>();
}
	: ^(BLOCK declaration* s+=statement_list?) -> echo(text={$s})
	;

statement_list
	: s+=statement+ -> echo(text={$s})
	;

expression_statement
	: e=expression -> echo(text={$e.st})
	;

selection_statement
	:	^(IF e=expression s1=statement s2=statement?)
		-> if(exp={$e.st},stmts_true={$s1.st},stmts_false={$s2.st},
			label={$FunctionScope::counter++})
	|	^(SWITCH expression statement)
	;

iteration_statement
	: ^(WHILE expression statement)
	| ^(DO expression statement)
	| ^(FOR e1=expression_statement e2=expression_statement e3=expression? s=statement)
		-> for(exp1={$e1.st},exp2={$e2.st},exp3={$e3.st},stmts={$s.st},label={$FunctionScope::counter++})
	;

jump_statement
	: ^(GOTO IDENTIFIER)
	| CONTINUE
	| BREAK
	| RETURN
	| ^(RETURN expression) // -> return(exp={$expression.st})
	;